package com.onpositive.mediawiki.propertyparser;

import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;

import storage.v1.DefaultParserProvider;


import com.onpositive.data.units.DateWithAccuracy;
import com.onpositive.semantic.model.api.meta.IMeta;
import com.onpositive.semantic.model.api.property.IPropertyProvider;
import com.onpositive.units.AbstractPreprocessor;
import com.onpositive.units.AbstractValueParser;
import com.onpositive.units.ParsedDate;
import com.onpositive.units.ParsedDimension;
import com.onpositive.units.ParsedIdent;
import com.onpositive.units.ParsedScalar;
import com.onpositive.units.ParsedString;
import com.onpositive.units.ParsedValue;
import com.onpositive.units.ParsedValueSequenceV2;
import com.onpositive.units.ValueCluster;

public class UnitParser extends AbstractValueParser {
	
	public UnitParser() {
		super("unit-parser");
		// TODO Auto-generated constructor stub
	}

	static private DimensionParser dimensionParser = new DimensionParser() ;
	
	public static ParsedValue parseStatically(String value, IMeta meta, IPropertyProvider propertyProvider,Map<String,Object> metaInfo, String comment) {
		
		StringTokenizer ts = new StringTokenizer(value, " ");
		String nextToken = ts.nextToken();

		DateFormat dateInstance = new SimpleDateFormat("dd MM yyyy", Locale.US );
		try {
			Date parse = dateInstance.parse(value);
			
			return new ParsedDate(parse, DateWithAccuracy.ACCURACY_DAY, getDefaultComment());
		} catch (Exception e) {
			dateInstance = new SimpleDateFormat("dd MMMM yyyy", Locale.US );
			try {
				Date parse = dateInstance.parse(value);
				return new ParsedDate(parse, DateWithAccuracy.ACCURACY_DAY, getDefaultComment());
			} catch (ParseException e1) {				
			}
			dateInstance = new SimpleDateFormat("MMMM yyyy", Locale.US );
			try {
				Date parse = dateInstance.parse(value);
				return new ParsedDate(parse, DateWithAccuracy.ACCURACY_MONTH, getDefaultComment());
			} catch (ParseException e1) {
				dateInstance = new SimpleDateFormat("yyyy MMMM", Locale.US );
				try {
					Date parse = dateInstance.parse(value);
					return new ParsedDate(parse, DateWithAccuracy.ACCURACY_MONTH, getDefaultComment());
				} catch (ParseException e2) {
				}
			}
			// TODO: handle exception
		}

		double doubleValue = 0.0;
		try {
			
			ParsedValue pv = dimensionParser.parse(value, meta, propertyProvider, metaInfo, comment ) ;
			if( hasValueType( pv, ParsedDimension.ID ) )
				return pv ;
			
			doubleValue = NumberFormat.getInstance(Locale.US).parse(nextToken).doubleValue();				
			{
				String vl=value.trim();
				for (int a=0;a<vl.length();a++){
					char charAt = vl.charAt(a);
					if (!Character.isDigit(charAt)&&charAt!='.'&&charAt!=','&&charAt!=' '){
						return identParser.parse(value, meta, propertyProvider, metaInfo, comment) ;
					}
				}
				return new ParsedScalar(doubleValue, getDefaultComment());
			}
		} catch (ParseException e) {
			ParsedValue pv = identParser.parse(value, meta, propertyProvider, metaInfo, comment) ;
			return pv;
		}
		
	}

	static private AbstractValueParser identParser = DefaultParserProvider.getInstance().getParser( ParsedIdent.ID) ;
	
	private static boolean hasValueType(ParsedValue pv, String vt)
	{
		String valType = pv.getMeta().getSingleValue( ParsedValue.META_KEY_VALUE_TYPE, String.class, null) ;

		if( valType == null )
			return false ;
		
		if( valType.equals( ParsedValueSequenceV2.ID ) ){
			ParsedValue[] valArr = ((ParsedValueSequenceV2)pv).getValuesArray() ;
			for( ParsedValue childVal : valArr )
				if( hasValueType(childVal, vt) )
					return true ;
				
			return false ;
		}
		else
			return valType.equals(vt) ; 
			
	}

	private static String getDefaultComment(){
		
		return UnitParser.class.getSimpleName() ;
	}

	@Override
	public ParsedValue parse(String s, IMeta meta, IPropertyProvider propertyProvider,Map<String,Object> metaInfo, String comment) {
		return parseStatically( s, meta, propertyProvider, metaInfo, comment) ;
	}
}
